package org.boulderfoodrescue.webapp.client.managers;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.boulderfoodrescue.webapp.client.events.ChangeType;
import org.boulderfoodrescue.webapp.client.events.OneTimeEventUpdatedEvent;
import org.boulderfoodrescue.webapp.client.events.OneTimeEventUpdatedHandler;
import org.boulderfoodrescue.webapp.client.events.RecurringEventUpdatedEvent;
import org.boulderfoodrescue.webapp.client.events.RecurringEventUpdatedHandler;
import org.boulderfoodrescue.webapp.client.rpc.TimeSlotServiceAsync;
import org.boulderfoodrescue.webapp.shared.Location;
import org.boulderfoodrescue.webapp.shared.OneTimeEvent;
import org.boulderfoodrescue.webapp.shared.RecurringEvent;

import com.google.gwt.event.shared.EventBus;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;

public class TimeSlotManager {
	private static TimeSlotServiceAsync timeslotRPC;
	private static EventBus eventBus;
	private static Map<Long, List<RecurringEvent>> recurringMap = new HashMap<Long, List<RecurringEvent>>();
	private static Map<Long, List<OneTimeEvent>> oneTimeMap = new HashMap<Long, List<OneTimeEvent>>();

	public TimeSlotManager(TimeSlotServiceAsync timeslotRPC, EventBus eventBus)
	{
		TimeSlotManager.timeslotRPC = timeslotRPC;
		TimeSlotManager.eventBus = eventBus;
		bind();
	}

	private void bind()
	{
		eventBus.addHandler(OneTimeEventUpdatedEvent.getType() , 
				new OneTimeEventUpdatedHandler(){
			@Override
			public void onOneTimeEventAdded(
					OneTimeEventUpdatedEvent event) {
				List<OneTimeEvent> list = oneTimeMap.get(event.getValue().getDatabaseKey());
				if(list == null){
					list = new LinkedList<OneTimeEvent>();
					list.add(event.getValue());
					oneTimeMap.put(event.getValue().getDatabaseKey(), list);
				}
				else
					list.add(event.getValue());

			}
			@Override
			public void onOneTimeEventUpdated(
					OneTimeEventUpdatedEvent event) {
				// TODO Auto-generated method stub
			}
			@Override
			public void onOneTimeEventRemoved(
					OneTimeEventUpdatedEvent event) {
				List<OneTimeEvent> list = oneTimeMap.get(event.getValue().getDatabaseKey());
				if(list != null)
					list.remove(event.getValue());
			}
		});

		eventBus.addHandler(RecurringEventUpdatedEvent.getType(), 
				new RecurringEventUpdatedHandler(){
			@Override
			public void onRecurringEventAdded(
					RecurringEventUpdatedEvent event) {
				List<RecurringEvent> list = recurringMap.get(event.getValue().getDatabaseKey());
				if(list == null){
					list = new LinkedList<RecurringEvent>();
					list.add(event.getValue());
					recurringMap.put(event.getValue().getDatabaseKey(), list);
				}
				else
					list.add(event.getValue());
			}
			@Override
			public void onRecurringEventUpdated(
					RecurringEventUpdatedEvent event) {
				// TODO Auto-generated method stub
			}
			@Override
			public void onRecurringEventRemoved(
					RecurringEventUpdatedEvent event) {
				List<RecurringEvent> list = recurringMap.get(event.getValue().getDatabaseKey());
				if(list != null)
					list.remove(event.getValue());
			}
		});
	}

	public static void SaveRecurringEvent(final RecurringEvent recurringEvent){
		timeslotRPC.saveRecurringEvent(recurringEvent, new AsyncCallback<RecurringEvent>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Can't Save Recurring Event");
			}

			@Override
			public void onSuccess(RecurringEvent result) {
				if(result == null)
					Window.alert("Can't Save Recurring Event on Server");
				else
				{
					eventBus.fireEvent(new RecurringEventUpdatedEvent(ChangeType.Added, result));
				}
			}

		});
	}

	public static void SaveOneTimeEvent(final OneTimeEvent oneTimeEvent){
		timeslotRPC.saveOneTimeEvent(oneTimeEvent, new AsyncCallback<Long>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Failed to save one time event");
			}

			@Override
			public void onSuccess(Long result) {
				if(result == null)
					Window.alert("Failed to save one time event");
				oneTimeEvent.setDatabaseKey(result);
				eventBus.fireEvent(new OneTimeEventUpdatedEvent(ChangeType.Added, oneTimeEvent));

			}
		});
	}

	public static List<RecurringEvent> getRecurringTimeSlots(final Location location) {
		if(location == null)
			return new LinkedList<RecurringEvent>();
		if(recurringMap.containsKey(location.getDatabaseKey()))
			return recurringMap.get(location.getDatabaseKey());
		timeslotRPC.getRecurringEvent(location.getDatabaseKey(), new AsyncCallback<List<RecurringEvent>>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Failed to load recurring events from server");
			}

			@Override
			public void onSuccess(List<RecurringEvent> result) {
				if(result == null)
					Window.alert("Failed to load recurring events");
				else{
					for(RecurringEvent e : result){
						eventBus.fireEvent(new RecurringEventUpdatedEvent(ChangeType.Added, e));
					}
				}
			}
		});
		return new LinkedList<RecurringEvent>();
	}

	public static List<OneTimeEvent> getOneTimeTimeSlots(final Location location) {
		if(location == null)
			return new LinkedList<OneTimeEvent>();
		if(oneTimeMap.containsKey(location.getDatabaseKey()))
			return oneTimeMap.get(location.getDatabaseKey());
		timeslotRPC.getOneTimeEvents(location.getDatabaseKey(), new AsyncCallback<List<OneTimeEvent>>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("Failed to load one time events from server");
			}

			@Override
			public void onSuccess(List<OneTimeEvent> result) {
				if(result == null)
					Window.alert("Failed to one time events");
				else{
					for(OneTimeEvent e : result)
						eventBus.fireEvent(new OneTimeEventUpdatedEvent(ChangeType.Added, e));
				}
			}
		});
		return new LinkedList<OneTimeEvent>();
	}
}
